// 升级玩法 插件

string author = "Live";
string pluginName = "UP 升级玩法插件";
string version = "0.2";

// 开启复活？
bool openRespawn = true;
// 复活的时间设置
int second = 30;


// 游戏结束标识位（如果游戏结束，终止复活）
bool gameover = false;

const array<int> respawnSecondConst = {second,second,second,second,second,second,second,second,second,second,second,second,second,second,second,second,second,second,second,second}; 
array<int> respawnSecond = respawnSecondConst;
// 这个数组是用来解决BUG问题的，复活标识，0 不能复活 1 能复活，防止因为各种正在复活时的突发重生行为（玩家被命令重生，防守模式中回合胜利的自动重生）
// 从而导致复活后倒计时复活还在运作导致再复活一次的BUG
array<bool> canRespawn = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false};

// 玩家经验值
array<int> exp(16);

// 每次升级需要的经验值（2级需要15经验，最高11级260）
array<int> NEXP = {15,30,50,75,100,125,155,190,225,260,999};

// 临时称号
array<string> name = {"{community}[手无缚鸡之力]","{axis}[星星之火]","{aqua}[灵魂后盾]","{blueviolet}[破局之矛]","{deeppink}[力挽狂澜]","{gold}[巅峰之境]"};

// 每个人分配的僵尸数(默认6)
int zf = 6;

// 插件初始化
void OnPluginInit()
{
    // 设置插件信息
    PluginData::SetAuthor(author);
    PluginData::SetName(pluginName);
    PluginData::SetVersion(version);

    // 提示
    ThePresident.InfoFeed("插件:"+pluginName+"| 版本:"+version+"| 作者:"+author,false);

    // 玩家连接后
    Events::Player::OnPlayerConnected.Hook( @OnPlayerConnected );
    // 玩家出生后
    Events::Player::OnPlayerSpawn.Hook( @OnPlayerSpawn );
    // 丧尸死亡后
    Events::Infected::OnInfectedKilled.Hook( @OnInfectedKilled );
    // 玩家说
    Events::Player::PlayerSay.Hook( @PlayerSay );
    // 玩家执行菜单
    Events::Player::OnMenuExecuted.Hook( @OnMenuExecuted );
    // 当玩家逃脱
    Events::Player::OnPlayerEscape.Hook( @OnPlayerEscape );
    // 当玩家抵达安全区
    Events::Player::OnPlayerReachSafeZone.Hook( @OnPlayerReachSafeZone );
    // 当玩家离开安全区
    Events::Player::OnPlayerLeftSafeZone.Hook( @OnPlayerLeftSafeZone );
    // 当回合终止时
    Events::ThePresident::OnTerminateRound.Hook( @OnTerminateRound );
    // 当玩家被杀死后
    Events::Player::OnPlayerKilledPost.Hook( @OnPlayerKilledPost );
    // 当玩家断开连接时
    Events::Player::OnPlayerDisconnected.Hook( @OnPlayerDisconnected );
    // 当没有存活的玩家时
    Events::ThePresident::OnNoSurvivorsRemaining.Hook( @OnNoSurvivorsRemaining );
    // 当实体创建时
    Events::Entities::OnEntityCreation.Hook( @OnEntityCreation );
    // 实体掉落
    Events::Player::OnEntityDropped.Hook( @OnEntityDropped );
    // 当从随机池创建物品时
    Events::ThePresident::OnRandomItemSpawn.Hook( @OnRandomItemSpawn );

    // 连接数据库
    ConnectToDB();

    ThePresident_OnMapStart();
}

// 数据库连接
CSQLConnection@ gMainConnection = null;

// 连接数据库
void ConnectToDB()
{
    // SQL Connection info
    string strSQLHost = "localhost"; // Our hostname
    int iPort = 0; // if iPort is 0, then it will use default MySQL port
    string strSQLUser = "root"; // Our username
    string strSQLPass = "lingfeng"; // Our password
    string strSQLDB = "contagion"; // Our database

    // Create our connection
    SQL::Connect( strSQLHost, iPort, strSQLUser, strSQLPass, strSQLDB, OnSQLConnect );
}

void OnSQLConnect( CSQLConnection@ pConnection )
{
    if ( pConnection.Failed() ) {
        ThePresident.InfoFeed("数据库连接失败！",false);
    }
    
    @gMainConnection = pConnection;
    ThePresident.InfoFeed("数据库连接成功！",false);
    Chat.PrintToConsole(all, "{green}数据库连接成功！");
    Log.PrintToServerConsole(LOGTYPE_INFO, "Database connected...");
	// 同步所有玩家数据
	playerList = Utils.CollectPlayers();
	for(uint i = 0;i<playerList.length();i++){
		CBasePlayer@ pPlayer = ToBasePlayer(playerList[i]);
		DB_synScore(pPlayer);
	}
	Chat.PrintToChat(all,"成功同步所有玩家金币");
}

// 当插件卸载
void OnPluginUnload()
{
    // 关闭数据库连接
    SQL::Disconnect(gMainConnection);
}

// 地图关闭时关闭连接
void OnMapShutdown()
{
    saveALLMoney();
	SQL::Disconnect( gMainConnection );
}

// 地图初始化时，重新连接
void OnMapInit()
{
	@gMainConnection = null;
	ConnectToDB();
}

// 当玩家加载完进入游戏
HookReturnCode OnPlayerConnected(CTerrorPlayer@ pPlayer)
{
    Chat.PrintToChat(pPlayer, "欢迎进入本服务器，该服务器玩法为升级玩法，简单介绍：击杀获取金币、经验升级，升级获得奖励选择以及提升人物血量（15）\n");
	Chat.PrintToChat(pPlayer, "并获得武器奖励.插件编写：{gold}Live {white}| 玩法策划：{hotpink}世界第一初恋、Live\n{gold}提示：!info查询，!b、!buy商店");
    DB_synScore(pPlayer);
    //Chat.PrintToChat(all,"当前玩家人数为:{gold}"+Utils.CollectPlayers().length());
	zombieConstant();
	return HOOK_CONTINUE;
}

void DB_synScore(CTerrorPlayer@ pPlayer){
    string steamid = Utils.Steam64ToSteam32(pPlayer.GetSteamID64());
    // 创建数据库信息
    string sql_addPlayer = "INSERT INTO `record`(steamid,name) "
    "SELECT '"+steamid+"','"+pPlayer.GetPlayerName()+"' FROM DUAL "
    "WHERE NOT EXISTS("
	"SELECT steamid "
	"FROM `record` "
	"WHERE steamid = '"+steamid+"'"
    ");";
    //Chat.PrintToChat(all,sql_addPlayer);
    SQL::SendQuery( gMainConnection, sql_addPlayer, addPlayer );

    // 设置玩家金币，同步
    string sql_queryPlayer = "select * from `record` where steamid = '"+steamid+"';";
    SQL::SendQuery( gMainConnection, sql_queryPlayer, setPlayerMoney );
}

void addPlayer(IMySQL@ pQuery){
    // If our query is null, then it failed.
    if ( pQuery is null ) return;

    // That means the table does not exist. Let's create our table then.
    if ( !pQuery.Failed() )
    {
        //Chat.PrintToChat(all,"添加玩家信息成功！");
    }else{
        //Chat.PrintToChat(all,"添加玩家信息失败！");
    }
}

void setPlayerMoney(IMySQL@ pQuery){
    if( pQuery is null ) return;
    if( !pQuery.Failed() ){
        string steamid = SQL::ReadResult::GetString( pQuery, "steamid" );
        CTerrorPlayer@ pPlayer = GetPlayerBySteamID(steamid);
        // 归 0
        pPlayer.AddScore(-pPlayer.GetScore());
        int money = SQL::ReadResult::GetInt( pQuery, "money" );
        pPlayer.AddScore(money);
        Log.PrintToServerConsole(LOGTYPE_INFO, "money---Synchronized");
    }
}

// 玩家出生
HookReturnCode OnPlayerSpawn(CTerrorPlayer@ pPlayer)
{
    if ( ThePresident.GetGameModeType() == 5){
        // 清空所有
        pPlayer.StripEquipment( true );
        // 给手机
        pPlayer.GiveWeapon( "phone" );
    }
    // 获取当前重生体的身份
    // 如果是人复活重生了
    if ( pPlayer.GetTeamNumber() == TEAM_SURVIVOR ){
        // 将复活标识设为false，防止因其它因素复活（命令复活、守卫模式回合复活）后还在倒计时复活的BUG
        int index = pPlayer.entindex();
        canRespawn[index-1] = false;
        // 重置复活时间
        respawnSecond[index-1] = second;
        playerHealth(pPlayer,selectLEVE(pPlayer));
        selectINFO(pPlayer);
        int leve = selectLEVE(pPlayer);
		if( leve < 11 ){
			MAXGIFT(pPlayer,leve);
		}else{
			MAXGIFT(pPlayer,11);
		}
        // 查询当前地图，连续图时不清装备
    }else{
        // 获取当前的游戏模式
        int gamemode = ThePresident.GetGameModeType();
        // 这个游戏中途加入的人会变成小强或者丧尸，为了让其复活
        // 如果游戏不是猎杀模式
        if( not (gamemode == CT_HUNTED) ){
            // 延时5秒调用检查方法，防止死亡的玩家一瞬间变成旁观者（守卫模式），复活时间还是second秒没来得及减少导致判断错误的BUG
            Schedule::Task(5.0f,pPlayer.entindex(),check);
        }
    }
	return HOOK_HANDLED;
}

// 用于检查玩家是否是不能复活的玩家
void check(int index){
    CTerrorPlayer@ pPlayer = ToTerrorPlayer( index );
    // 获取当前玩家的身份
    int TeamNumber = pPlayer.GetTeamNumber();
    //Chat.PrintToChat(all,""+TeamNumber);
    // 如果当前玩家身份是旁观者或者丧尸（再判断一次，防止是0）
    if(TeamNumber == TEAM_SPECTATOR || TeamNumber == TEAM_ZOMBIE){
        // 先判断是否开启了复活
        if( openRespawn ){
            // 判断该角色的复活时间是不是second（正在复活会减少时间，调用前已延迟5秒防止速度太快误判），即可分辨是死亡后正在复活的小强或者丧尸，还是中途进入没在复活的小强
            if(respawnSecond[index-1] == second){
                if(!gameover){
                    // 复活玩家
                    respawnPlayer(index);
                    Chat.PrintToChat(all, "{gold}[{green}Live{gold}]{white}:检测到玩家["+pPlayer.GetPlayerName()+"]加入时为小强或丧尸，已自动得到重新做人的机会" );
                }
            }
        }else{
            Chat.PrintToChat(pPlayer,"{hotpink}当前模式为硬核模式，复活关闭，请耐心等待队友，不要退出游戏(Resurrection closed, waiting for teammates to die or escape)....");
        }
    }
}


//array<int> money(16);

HookReturnCode OnInfectedKilled(Infected@ pInfected, CTakeDamageInfo &in DamageInfo)
{
    CBaseEntity@ pAttacker = DamageInfo.GetAttacker();	//获取攻击者信息
    CTerrorPlayer@ pPlayer = ToTerrorPlayer(pAttacker);	//转换攻击者为玩家属性
    
    // 查询未击杀前的等级
    int oldLEVE = selectLEVE(pPlayer);
    // 如果已经11级了，那就看看经验除以15的除数是否+1
    int oldChu = (exp[pPlayer.entindex()-1] - 260)/35;

    // 检查武器是否有加钱BUFF
    bool MoneyBoost = false;
    string WeaponName = "";
    CBaseEntity@ cWeapon = DamageInfo.GetWeapon();
    if(cWeapon.GetClassname() != "grenade_projectile"){
        CTerrorWeapon@ Weapon = ToTerrorWeapon(cWeapon);
        MoneyBoost = Weapon.UpgradeModule(HAS, k_eMoneyBoost);
        WeaponName = Weapon.GetClassname();
    }
    // 防爆僵尸，玩家增加3经验，普通僵尸增加1经验
    if( pInfected.IsRiot() ){
        // 如果是近战，双倍经验
        if( WeaponName == "weapon_melee" )
            exp[ pPlayer.entindex()-1 ] +=6;
        else
            exp[ pPlayer.entindex()-1 ] +=3;
        if( MoneyBoost )
            pPlayer.AddScore(8);
        else
            pPlayer.AddScore(4);
    }else{
        if( WeaponName == "weapon_melee" )
            exp[ pPlayer.entindex()-1 ] +=2;
        else
            exp[ pPlayer.entindex()-1 ] +=1;
        if( MoneyBoost )
            pPlayer.AddScore(4);
        else
            pPlayer.AddScore(2);
    }
    // 击杀后的等级
    int newLEVE = selectLEVE( pPlayer );
    // 击杀后的除数
    int newChu = (exp[pPlayer.entindex()-1] - 260)/35;
    
    // 判断是否升级
    if( oldLEVE != newLEVE ){
        // 重新设置血量
        playerHealth( pPlayer,newLEVE );
        // 奖励选择
        MAXGIFT(pPlayer,newLEVE);
        Chat.PrintToChat(all,"玩家[{green}"+pPlayer.GetPlayerName()+"{white}]升级到了{red}"+newLEVE+"{white}级,玩家称号"+selectNAME(newLEVE)+" {hotpink}提升生命值");       
    }

    // 如果已经满级
    if( oldLEVE == 11 ){
        if( oldChu == (newChu-1) ){
            MAXGIFT( pPlayer,11 );
            Chat.PrintToChat(all,"玩家[{green}"+pPlayer.GetPlayerName()+"{white}]已满级，（每获得15经验）奖励全类型弹药与BUFF");
        }
    }

    //Chat.PrintToChat(all,"BUG测试，检查完成了");
	return HOOK_HANDLED;
}

// 查询等级
int selectLEVE(CTerrorPlayer@ pPlayer){
    int playerEXP = exp[ pPlayer.entindex()-1 ];
    int leve = 1;
    for( uint i=0;i<10;i++ ){
        if( playerEXP >= NEXP[i] ){
            leve++;
        }else{
            break;
        }
    }
    // Chat.PrintToChat(all,"等级"+leve);
    return leve;
}

// 查询称号
string selectNAME(int leve){
    string Tname;
    if( leve <= 2 ){
        Tname = name[0];
    }else if( leve <= 5 ){
        Tname = name[1];
    }else if( leve <= 8 ){
        Tname = name[2];
    }else if( leve <= 9 ){
        Tname = name[3];
    }else if( leve <= 10 ){
        Tname = name[4];
    }else if( leve >= 11 ){
        Tname = name[5];
    }
    // Chat.PrintToChat(all,"称号"+Tname);
    return Tname;
}

// 查询玩家信息
void selectINFO(CTerrorPlayer@ pPlayer){
    int leve = selectLEVE(pPlayer);
    string Tname = selectNAME(leve);
    Chat.PrintToChat(all,"玩家[{green}"+pPlayer.GetPlayerName()+"{white}] 经验[{red}"+exp[ pPlayer.entindex()-1 ]+"{green}/{red}"+NEXP[leve-1]+"{white}] 等级["+leve+"{white}] 称号"+Tname+"{white} 金币[{gold}"+pPlayer.GetScore()+"{white}] 生命值 [{green}"+pPlayer.GetHealth()+"{white}]");
}

// 设置玩家血量
void playerHealth(CTerrorPlayer@ pPlayer,int leve){
    // 噩梦难度一下的伤害
    int health = 48;
    int UpHealth;
    if(leve > 6){
        UpHealth = health * 6;
    }else{
        UpHealth = health * leve;
    } 
    pPlayer.SetMaxHealth( UpHealth );
    pPlayer.SetHealth( UpHealth );
}

HookReturnCode PlayerSay(CTerrorPlayer@ pPlayer, CASCommand@ pArgs)
{
    string arg = pArgs.Arg( 1 );
	string arg1 = "";
	string arg2 = "";

	// 切分字符串(这样就可以用空格传一个命令参数了)
	int subIndex = arg.findFirst(" ",0);
	if(not (subIndex < 0)){
		arg1 = arg.substr(0,subIndex);
		arg2 = arg.substr(subIndex+1,-1);
		//Chat.PrintToChat(all,""+arg1+"|"+arg2);
	}else{
		arg1 = arg;
	}

    if( AdminSystem.AdminExist(pPlayer) ){
        if(arg1 == "!exp"){
            if( arg2!="" ){
                exp[pPlayer.entindex()-1] += Utils.StringToInt(arg2);
                playerHealth(pPlayer,selectLEVE(pPlayer));
            }
        }else if(arg1 == "!give"){
            if( arg2!="" ){
                pPlayer.GiveWeapon(arg2);
            }
        }else if(arg1 == "!fh"){
            if( not Utils.StrEql( arg2, "" ) ){
                if( arg2 == "all" ){
                    array<int> playerList = Utils.CollectPlayers();
                    for(uint i=0;i<playerList.length();i++){
                        CTerrorPlayer@ player = ToTerrorPlayer(playerList[i]);
                        if(not (player.GetTeamNumber() == TEAM_SURVIVOR)){
                            if( canRespawn[player.entindex()-1] ){
                                respawnPlayer(playerList[i]);
                            }
                        }
                    }
                    Chat.PrintToChat(all,"管理员复活了所有玩家");
                }else{
                    CTerrorPlayer@ splayer = ToTerrorPlayer( parseInt(arg2,10,0) );
                    if(splayer is null) return HOOK_CONTINUE;
                    // 修改被复活玩家的游戏阵营
                    splayer.ChangeTeam( TEAM_SURVIVOR );
                    // 复活玩家
                    splayer.Respawn();
                    Chat.PrintToChat(all,"{hotpink}管理员使用命令复活了["+splayer.GetPlayerName()+"]");
                }
			}else{
				// 修改被复活玩家的游戏阵营
				pPlayer.ChangeTeam( TEAM_SURVIVOR );
				// 复活玩家
				pPlayer.Respawn();
			}
        }else if(arg1 == "!g"){
			MAXGIFT(pPlayer,selectLEVE(pPlayer));
        }else if( arg1 == "!mf" ){
            if( arg2 != "" ){
                mf = Utils.StringToInt(arg2);
            }
        }else if(arg1 == "!k"){
            Engine.RunConsoleCommand( "admin slay !" + pPlayer.entindex() );
        }else if(arg1 == "!m"){
            if(arg2!=""){
                pPlayer.AddScore(Utils.StringToInt(arg2));
            }
        }else if(arg1 == "!zc"){
            if(arg2!=""){
                ThePresident.SetSpawnConstantFlags(ZSF_FORCED_AREA);
                ThePresident.SetSpawnZombiesConstant(parseInt(arg2,10,0));
                Chat.PrintToChat(pPlayer,"设置丧尸常量"+arg2+"只");
                zombieC = parseInt(arg2,10,0);
            }
        }else if(arg1=="!re"){
            openRespawn = !openRespawn;
            Chat.PrintToChat(pPlayer,"复活"+openRespawn);
        }else if(arg1=="!tili"){
            CASConVarRef@ infiniteStamina= ConVar::Find( "sv_infinite_stamina" );
            if( test_infiniteStamina ){
                infiniteStamina.SetValue("0");
                Chat.PrintToChat( all,"{hotpink}无限体力关闭" );
            }else{
                infiniteStamina.SetValue("1");
                Chat.PrintToChat( all,"{hotpink}无限体力开启" );
            }
            test_infiniteStamina = ! test_infiniteStamina;
        }else if(arg1 == "!ammo"){
            CASConVarRef@ sv_infinite_collected_ammo = ConVar::Find( "sv_infinite_collected_ammo" );
            if( test_infiniteCollectedAmmo ){
                sv_infinite_collected_ammo.SetValue("0");
                Chat.PrintToChat(pPlayer,"{hotpink}无限备弹关闭");
            }else{
                sv_infinite_collected_ammo.SetValue("1");
                Chat.PrintToChat(pPlayer,"{hotpink}无限备弹开启");
                //removeAllAmmo();
                //Chat.PrintToChat(all,"{hotpink}已清除地图所有子弹");
            }
            test_infiniteCollectedAmmo = ! test_infiniteCollectedAmmo;
        }else if(arg1=="!suo"){
            if( ThePresident.IsHordeMode() ){
                ThePresident.StopHordeMode();
                Horde = false;
                Chat.PrintToChat( pPlayer,"{hotpink}Horde模式已关闭" );                    
            }else{
                ThePresident.BeginHordeMode();
                Horde = true;
                Chat.PrintToChat( pPlayer,"{hotpink}Horde模式已启动（全局锁人）" );
            }
        }else if( arg1 == "!zf" ){
            if( arg2 != "" ){
                zf = Utils.StringToInt(arg2);
                zombieConstant();
                Chat.PrintToChat(all,"已设置每人分配"+zf+"个僵尸");
            }
        }
    }
    if(arg1 == "!b" || arg1 == "!buy" || arg1 == "！b"){
        SHOP(pPlayer);
    }else if(arg1 == "!info"){
        selectINFO(pPlayer);
    }else{
        // 玩家专属称号
        if( pPlayer.GetSteamID64() == "76561199221153384"){
            Chat.PrintToChat(all,"{deeppink}[服主]{lime}[Contagion插件作者] "+selectNAME(selectLEVE(pPlayer))+" "+pPlayer.GetPlayerName()+" : "+arg);
        }else if( pPlayer.GetSteamID64() == "76561198311292986" ){
            Chat.PrintToChat(all,"{hotpink}[玩法策划]{unique}[赞助VIP] "+selectNAME(selectLEVE(pPlayer))+" "+pPlayer.GetPlayerName()+" : "+arg);
            // 76561199149736894 聆听夏的味道 76561199405413662 nmsl 76561198135257879 雪ノ下 樹海♬ 76561198322158804 奇迹行者
        }else if( pPlayer.GetSteamID64() == "76561199149736894" || pPlayer.GetSteamID64() == "76561199405413662" || pPlayer.GetSteamID64() == "76561198135257879" || pPlayer.GetSteamID64() == "76561198322158804"){
            Chat.PrintToChat(all,"{unique}[赞助VIP] "+selectNAME(selectLEVE(pPlayer))+" "+pPlayer.GetPlayerName()+" : "+arg);
        }else if( pPlayer.GetSteamID64() == "76561198884797182" ){
            Chat.PrintToChat(all,"{unique}[鸽子白] "+selectNAME(selectLEVE(pPlayer))+" "+pPlayer.GetPlayerName()+" : "+arg);
        }else{
            Chat.PrintToChat(all,selectNAME(selectLEVE(pPlayer))+" "+pPlayer.GetPlayerName()+" : "+arg);
        }
    }
	return HOOK_HANDLED;
}

array<array<string>> Gift = {
    {"斧头","镰刀"},
    {"小刀","左轮","加兰德"},
    {"警棍","1911手枪","kg9手枪","双管喷"},
    {"勃朗宁步枪","西格绍尔手枪","雷明顿大狙"},
    {"mac10冲锋枪","雷明顿870喷","键盘"},
    {"莫斯伯格喷","mp5k冲锋枪"},
    {"ACR步枪","弩","复合喷"},
    {"AK74U","复合弓"},
    {"SCAR","连喷","沙鹰"},
    {"AR15","榴弹"},
    {"当前武器双倍伤害","双倍金钱","喷火器"}
};

array<array<string>> GiftName = {
    {"FireAxe","Scythe"},
    {"Kabar","Revolver","M1garand"},
    {"Baton","1911","kg9","doublebarrel"},
    {"blr","sig","sniper"},
    {"mac10","remington870","Keyboard"},
    {"Mossberg","mp5k"},
    {"acr","crossbow","overunder"},
    {"ak74","compbow"},
    {"scar","autoshotgun","handcannon"},
    {"ar15","grenadelauncher"},
    {"当前武器双倍伤害","双倍金钱","喷火器"}
};

// 满级专属奖励
void MAXGIFT(CTerrorPlayer@ pPlayer,int leve){
	// 如果是恐慌模式，拿等级+1的奖励
	int CT_PAINC = 5;
	if( ThePresident.GetGameModeType() ==  CT_PAINC && leve < 11){
		leve += 1;
	}
		
    Menu pMenu;
    pMenu.SetTitle("奖励选择");
    pMenu.SetID("MAX"+leve);
    for(uint i=0;i<Gift[leve-1].length();i++){
        pMenu.AddItem(Gift[leve-1][i]);
    }
    if( selectLEVE(pPlayer) == 11 ){
        if( leve > 1 ){
            pMenu.SetBack( true );
        }
        if( leve < 11 )
            pMenu.SetNext( true );
        }
    pMenu.Display( pPlayer, -1 );
    return;
}

void SHOP(CTerrorPlayer@ pPlayer){
    Menu pMenu;
    pMenu.SetID("SHOP");
    pMenu.SetTitle("商店");
    pMenu.AddItem("加满所有子弹"+30*mf+"（需要留一格）");
    pMenu.AddItem("复活死亡队友（1个"+20*mf+"）");
    pMenu.AddItem("医疗包"+40*mf);
    pMenu.AddItem("手雷"+10*mf);
    pMenu.AddItem("复活自己"+60*mf);
    pMenu.AddItem("手电筒"+10*mf);
    pMenu.Display(pPlayer,-1);
}

array<int> playerList;

int mf = 1;

HookReturnCode OnMenuExecuted(CTerrorPlayer@ pPlayer, const string &in szID, int &in iValue)
{
    if(szID == "SHOP"){
        switch( iValue ){
            // 购买子弹
            case 1:{
                int price = 30 * mf;
                if( pPlayer.GetScore() >= price ){
                    if(pPlayer.GiveWeapon("ammo"))
                        pPlayer.AddScore(-price);
                    else
                        Chat.PrintToChat(pPlayer,"{hotpink}背包空间不够");
                }else{
                    Chat.PrintToChat(pPlayer,"{hotpink}金币不够");
                }
                break;
            }
            // 复活队友
            case 2:{
                if( pPlayer.GetTeamNumber() == TEAM_SURVIVOR ){
                    int price = 20 * mf;
                    if( pPlayer.GetScore() >= price ){
                        playerList = Utils.CollectPlayers();
                        for( uint i=0;i<playerList.length();i++ ){
                            CTerrorPlayer@ bePlayer = ToTerrorPlayer(playerList[i]);
                            if( bePlayer.GetTeamNumber() != TEAM_SURVIVOR ){
                                // 修改被复活玩家的游戏阵营
                                // 判断能否复活（防止复活已逃离的玩家）
                                if( canRespawn[playerList[i]-1] ){
                                    bePlayer.ChangeTeam( TEAM_SURVIVOR );
                                    // 复活玩家
                                    bePlayer.Respawn();
                                    Vector vector = pPlayer.GetAbsOrigin();
                                    bePlayer.SetAbsOrigin(vector);
                                }
                            }
                        }
                        Chat.PrintToChat(all,"[{green}"+pPlayer.GetPlayerName()+"{white}]购买了死亡玩家复活");
                    }else{
                        Chat.PrintToChat(pPlayer,"{hotpink}金币不够");
                    }
                }else{
                    Chat.PrintToChat( pPlayer,"{hotpink}只有当人的时候才能复活队友" );
                }
                break;
            }
            // 医疗包
            case 3:{
                int price = 40 * mf;
                if( pPlayer.GetScore() >= price ){
                    if(pPlayer.GiveWeapon("firstaid"))
                        pPlayer.AddScore(-price);
                }else{
                    Chat.PrintToChat(pPlayer,"{hotpink}金币不够");
                }
                break;
            }
            // 手雷
            case 4:{
                int price = 10 * mf;
                if( pPlayer.GetScore() >= price ){
                    if(pPlayer.GiveWeapon("grenade"))
                        pPlayer.AddScore(-price);
                }else{
                    Chat.PrintToChat(pPlayer,"{hotpink}金币不够");
                }
                break;
            }
            // 复活自己
            case 5:{
                int price = 60 * mf;
                if( pPlayer.GetScore() >= price ){
                    Open_PlayerShop_Tele(pPlayer);
                }else{
                    Chat.PrintToChat(pPlayer,"{hotpink}金币不够");
                }
                break;
            }
            case 6:{
                int price = 10 * mf;
                if( pPlayer.GetScore() >= price ){
                    CBaseEntity@ BaseWeapon = pPlayer.GetCurrentWeapon();
                    CTerrorWeapon@ Weapon = ToTerrorWeapon(BaseWeapon);
                    Weapon.SetAttachment(k_eFlashlight, true);
                    Chat.PrintToChat(pPlayer,"{hotpink}购买成功！请切换武器刷新");   
                }else{
                    Chat.PrintToChat(pPlayer,"{hotpink}金币不够");
                }
                break;
            }
        }
    }else if( Utils.StrContains("Menu_PlayerShop_Tele_Select", szID)){
        // 得到下标
        CASCommand@ arg = StringToArgSplit(szID, ";");
        int index =  Utils.StringToInt(arg.Arg(1));
        if(iValue == 8){
            // 如果是0则第一页，返回就是返回玩家商店
            if( index == 0 )
                SHOP(pPlayer);
            else
                Menu_PlayerShop_Tele(pPlayer,index-7);
        }else if(iValue == 9){
            Menu_PlayerShop_Tele(pPlayer,index+7);
        }else if(iValue>0 && iValue<8){
            iValue = iValue + index;
            if( pPlayer.GetTeamNumber() != TEAM_SURVIVOR ){
                int pPlayerIndex = playerList[iValue-1];
                if(pPlayerIndex == pPlayer.entindex()){
                    Chat.PrintToChat(pPlayer,"{hotpink}请选择除自己之外的人");
                }else{
                    // 修改被复活玩家的游戏阵营
                    pPlayer.ChangeTeam( TEAM_SURVIVOR );
                    // 复活玩家
                    pPlayer.Respawn();
                    CBasePlayer@ telePlayer = ToBasePlayer(pPlayerIndex);
                    Vector teleV = telePlayer.GetAbsOrigin();
                    pPlayer.SetAbsOrigin(teleV);
                    Chat.PrintToChat(all,"{hotpink}"+pPlayer.GetPlayerName()+"复活了自己到"+telePlayer.GetPlayerName());
                    int price = 30 * mf;
                    pPlayer.AddScore(-price);
                }
            }else{
                Chat.PrintToChat(pPlayer,"{hotpink}人死才能复生");
            }
        }
    }else if( Utils.StrContains( "MAX",szID ) ){
        //Chat.PrintToChat(all,"执行菜单");
        int subIndex = szID.findFirst("MAX",0);
        //Chat.PrintToChat(all,""+subIndex);
	    int	leve = Utils.StringToInt(szID.substr(subIndex+3,-1));
        //Chat.PrintToChat(all,""+leve);
        if( iValue < 8 && iValue !=0 ){
            if( leve < 11 ){
                string WeaponName = GiftName[leve-1][iValue-1];
                if(pPlayer.GiveWeapon( "ammo" )){
                    pPlayer.GiveWeapon( WeaponName );
                    Chat.PrintToChat(all,"[{green}"+pPlayer.GetPlayerName()+"{white}]获得了奖励武器[{gold}"+Gift[leve-1][iValue-1]+"{white}],并获得{gold}全类型子弹");
                }
                else{
                    Chat.PrintToChat(pPlayer,"{hotpink}背包已满，请留出一个空间再选择奖励");
                    MAXGIFT(pPlayer,leve);
                }
            }else{
                CBaseEntity@ BaseWeapon = pPlayer.GetCurrentWeapon();
                CTerrorWeapon@ Weapon = ToTerrorWeapon(BaseWeapon);
                switch( iValue ){
                    case 1:{
                        if(pPlayer.GiveWeapon("ammo")){
                            Weapon.UpgradeModule(SET,k_eDoubleDamage);
                            Chat.PrintToChat(all,"[{green}"+pPlayer.GetPlayerName()+"{white}]获得了奖励[{gold}"+Gift[10][iValue-1]+"{white}],并获得{gold}全类型子弹");
                        }else{
                            Chat.PrintToChat(pPlayer,"{hotpink}背包已满，请留出一个空间再选择奖励");
                            MAXGIFT(pPlayer,leve);
                        }
                        break;
                    }
                    case 2:{
                        if(pPlayer.GiveWeapon("ammo")){
                            Weapon.UpgradeModule(SET,k_eMoneyBoost);
                            Chat.PrintToChat(all,"[{green}"+pPlayer.GetPlayerName()+"{white}]获得了奖励[{gold}"+Gift[10][iValue-1]+"{white}],并获得{gold}全类型子弹");
                        }else{
                            Chat.PrintToChat(pPlayer,"{hotpink}背包已满，请留出一个空间再选择奖励");
                            MAXGIFT(pPlayer,leve);
                        }
                        break;
                    }
                    case 3:{
                        if(pPlayer.GiveWeapon( "ammo" )){
                            int x = pPlayer.GetWeaponSlot("weapon_flamethrower");
                            if( x != -1){
                                CBaseEntity@ cWeapon = pPlayer.GetWeaponFromSlot(x);
                                CTerrorWeapon@ thisWeapon = ToTerrorWeapon(cWeapon);
                                //Chat.PrintToChat(all,""+Weapon.m_iClip);
                                thisWeapon.m_iClip = 100;
                            }
                            pPlayer.GiveWeapon("flamethrower");
                            Chat.PrintToChat(all,"[{green}"+pPlayer.GetPlayerName()+"{white}]获得了奖励武器[{gold}喷火器{white}],并获得{gold}全类型子弹");
                        }
                        else{
                            Chat.PrintToChat(pPlayer,"{hotpink}背包已满，请留出一个空间再选择奖励");
                            MAXGIFT( pPlayer,leve );
                        }
                    }
                }
            }
        }
        switch( iValue ){
            case 8:{
				// 如果是恐慌模式，因为本来就拿的是后一级的奖励，所以拿上一级得多减1
				int CT_PAINC = 5;
				if( ThePresident.GetGameModeType() ==  CT_PAINC )
					MAXGIFT(pPlayer,leve-2);
				else
					MAXGIFT(pPlayer,leve-1);
                break;
            }
            case 9:{
                MAXGIFT(pPlayer,leve+1);
                break;
            }
        }
    }
    saveMoney(pPlayer);
	return HOOK_CONTINUE;
}

// 打开玩家传送菜单（index从0开始）
void Open_PlayerShop_Tele(CTerrorPlayer@ pPlayer){
    Menu_PlayerShop_Tele(pPlayer,0);
}

// 玩家传送菜单
void Menu_PlayerShop_Tele(CTerrorPlayer@ pPlayer,int index){
    if (pPlayer is null ) return;
    playerList = Utils.CollectPlayers();
    Menu pMenu;
	pMenu.SetID( "Menu_PlayerShop_Tele_Select;"+index );
	pMenu.SetTitle( "@请选择复活到谁@" );
    // 内容填充方法（填充玩家）
    Player_ItemFill(pPlayer,pMenu,index);
}

// 内容填充方法，从index开始
void Player_ItemFill(CTerrorPlayer@ pPlayer,Menu pMenu,int index){
    // 计数
    int count = 0;
    for(uint i=index;i<playerList.length();i++){
        CBasePlayer@ player = ToBasePlayer(playerList[i]);
        pMenu.AddItem(""+player.GetPlayerName());
        // 因为菜单一页只能有七个
        if(count>6) break;
        count++;
    }
    pMenu.SetBack( true );
    // 如果大于7项，就有下一页按钮
    if(count>6){
        pMenu.SetNext( true );
    }
    pMenu.Display( pPlayer, -1 );
}

HookReturnCode OnPlayerEscape(CTerrorPlayer@ pPlayer)
{
    // If the player escapes, I need to make some records
    pPlayer.AddScore(50);
    Chat.PrintToChat(all,"已奖励玩家{green}["+pPlayer.GetPlayerName()+"]{gold}50金币");
    //Chat.PrintToChat(all,"执行了逃脱hook");
    updateEscape(pPlayer);
    // 设置不能复活（用于解决逃离后被复活的BUG）
    canRespawn[pPlayer.entindex()-1] = false;
	return HOOK_CONTINUE;
}

void saveMoney(CTerrorPlayer@ pPlayer){
    string steamid = Utils.Steam64ToSteam32(pPlayer.GetSteamID64());
    string sql_saveMoney = "update `record` set money = "+pPlayer.GetScore()+" where steamid = '"+steamid+"';";
    SQL::SendQuery( gMainConnection, sql_saveMoney);
}

void updateEscape(CTerrorPlayer@ pPlayer){
    string steamid = Utils.Steam64ToSteam32(pPlayer.GetSteamID64());
    string sql_updateEscapeCount = "update `record` set escapeCount = escapeCount+1 where steamid = '"+steamid+"';";
    SQL::SendQuery( gMainConnection, sql_updateEscapeCount);
}

// 是否已保存
bool isSave = false;

// 当玩家抵达安全区
HookReturnCode OnPlayerReachSafeZone(CTerrorPlayer@ pPlayer)
{
    Chat.PrintToChat(all,"玩家{green}"+pPlayer.GetPlayerName()+"抵达安全区");
    if( !isSave ){
        saveALLMoney();
        isSave = true;
    }
	return HOOK_CONTINUE;
}

// 当玩家离开安全区
HookReturnCode OnPlayerLeftSafeZone(CTerrorPlayer@ pPlayer)
{
    Chat.PrintToChat(all,"玩家离开安全区");
	return HOOK_CONTINUE;
}

// 回合终止时
HookReturnCode OnTerminateRound(int iTeam)
{
    saveALLMoney();
    // 重置经验
    exp = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
	return HOOK_CONTINUE;
}

void saveALLMoney(){
    // 保存所有玩家的当前金币
    playerList = Utils.CollectPlayers();
    for(uint i=0;i<playerList.length();i++){
        CTerrorPlayer@ pPlayer = ToTerrorPlayer(playerList[i]);
        string steamid = Utils.Steam64ToSteam32(pPlayer.GetSteamID64());
        string sql_saveMoney = "update `record` set money = "+pPlayer.GetScore()+" where steamid = '"+steamid+"';";
        SQL::SendQuery( gMainConnection, sql_saveMoney);
    }
    Chat.PrintToChat(all,"{green}[数据库]:{hotpink}已保存所有玩家金币值");
}

// 地图开始
void ThePresident_OnMapStart(){
    // 服务器中文名
    Engine.RunConsoleCommand( "hostname [CN.Live] 特殊 升级自选商店复活 up QQ群392635015");
    // 设置难度
    Engine.RunConsoleCommand( "Difficulty 4");
    // 设置无法投票更改难度
    Engine.RunConsoleCommand( "sv_vote_issue_change_difficulty_allowed 0" );
    // 执行回合开始
    ThePresident_OnRoundStart();
}


// 无限备弹？
bool test_infiniteCollectedAmmo = false;
// 无限体力？
bool test_infiniteStamina = false;
// 僵尸锁人？
bool Horde = false;
// 僵尸常量
int zombieC = 0;

// 回合开始
void ThePresident_OnRoundStart()
{
    gameover = false;
    // 仅AI丧尸（玩家死亡不会变丧尸）
    Engine.RunConsoleCommand( "cg_zombie_ai_only 1" );
    // 无感染
    Engine.RunConsoleCommand( "cg_infection_disabled 1" );
    // 重置玩家金币
    array<int> players = Utils.CollectPlayers();
    for(uint i =0;i < players.length();i++){
        CTerrorPlayer@ player = ToTerrorPlayer(players[i]);
        int score = player.GetScore();
        // 只将负债的清除为0
        if(score < 0){
            player.AddScore(-score);
        }
    }

    // 检查是否开启无限体力
    infiniteStamina();

    // 检查是否开启无限子弹
    sv_infinite_collected_ammo();

    // 检查是否开启僵尸锁人
    checkHorde();

    // 检查是否开启僵尸常量
    zombieConstant();

    // 保存重置
    isSave = false;

    // 置空系统发的武器
    ThePresident.AddSpawnWeaponOverride(0, "", 0, 0);
}


// 无限体力
void infiniteStamina(){
    // 如果无限体力开启，执行一次（防止因为防卫模式把无限体力关了）
    if(test_infiniteStamina){
        CASConVarRef@ infiniteStamina= ConVar::Find( "sv_infinite_stamina" );
        infiniteStamina.SetValue("1");
        Chat.PrintToChat(all,"{hotpink}已自动开启无限体力");
    }
}

// 无限子弹
void sv_infinite_collected_ammo(){
    // 如果无限子弹开启，执行
    CASConVarRef@ infiniteStamina= ConVar::Find( "sv_infinite_collected_ammo" );
    if(test_infiniteCollectedAmmo){
        infiniteStamina.SetValue("1");
        Chat.PrintToChat(all,"{hotpink}已自动开启无限子弹");
        // 因为无法区别钉枪木板（也属于子弹），防止删除木板资源，故不再清除地图子弹
        //removeAllAmmo();
        //Chat.PrintToChat(all,"{hotpink}已清除地图所有子弹");
    }else{
        infiniteStamina.SetValue("0");
        Chat.PrintToChat(all,"{hotpink}已自动关闭无限子弹");
    }
}

// 锁人
void checkHorde(){
    if(Horde){
        ThePresident.BeginHordeMode();
        Chat.PrintToChat(all,"{hotpink}已自动开启Horde");
    }else{
        ThePresident.StopHordeMode();
        Chat.PrintToChat(all,"{hotpink}已自动关闭Horde");
    }
}

// 僵尸常量
void zombieConstant(){
    zombieC = Utils.CollectPlayers().length() * zf;
    if(zombieC != 0 ){
        ThePresident.SetSpawnConstantFlags(ZSF_FORCED_AREA);
        if( zombieC >= 60 ){
            ThePresident.SetSpawnZombiesConstant(60);
        }else{
            ThePresident.SetSpawnZombiesConstant(zombieC);
        }
        //Chat.PrintToChat(all,"{hotpink}已自动设置僵尸常量为"+zombieC+".每多一人，增加5只，最多40");
    }
}


// 死亡掉一级经验
HookReturnCode OnPlayerKilledPost(CTerrorPlayer@ pPlayer)
{
    // 小于15经验（1级）扣7，其它扣10
    int thisEXP = exp[pPlayer.entindex()-1];
    if(thisEXP < 15){
        if( thisEXP <= 7 )
            exp[pPlayer.entindex()-1] = 0;
        else
            exp[pPlayer.entindex()-1] -=7;
    }
    else
        exp[pPlayer.entindex()-1] -=10;
    // 输出提示信息
    Chat.CenterMessage(all,"["+pPlayer.GetPlayerName()+"]的屁股被丧尸给撅了...(["+pPlayer.GetPlayerName()+"]has died)");
    // 输出测试信息
    Chat.PrintToConsole(all,pPlayer.GetPlayerName()+" 死亡");
    //Chat.PrintToConsole(all,"[Live]插件测试信息(respawnSecond):"+respawnSecond[0]+respawnSecond[1]+respawnSecond[2]+respawnSecond[3]+respawnSecond[4]+respawnSecond[5]+respawnSecond[6]+respawnSecond[7]);
    Chat.PrintToConsole(all,"[Live]插件测试信息(index):"+pPlayer.entindex());
    // 如果开启了复活
    if( openRespawn ){
        // 获取玩家身份
        int TeamNumber = pPlayer.GetTeamNumber();
        // 是人才给复活，防止BUG
        if(TeamNumber == TEAM_SURVIVOR){
            int index = pPlayer.entindex();
            // 设置复活标识位为真
            canRespawn[index-1] = true; 
            // 开始倒计时方法
            Schedule::Task( 0.0f, pPlayer.entindex(), tip );
        }
    }
	return HOOK_CONTINUE;
}


//提示死亡计时
void tip(int index){ 
    // 游戏是否结束
    if( not gameover ){
        // 该玩家的复活标识位，以便其它事件随时终止复活
        if( canRespawn[index-1] ){
            // 倒计时提示玩家
            CBasePlayer@ pPlayer = ToBasePlayer( index );
            Chat.CenterMessagePlayer(pPlayer,respawnSecond[index-1]+"秒后复活...(Waiting for resurrection "+respawnSecond[index-1]+")");
            // 递减该玩家对应数组中的时间
            respawnSecond[index-1]--;
            // 倒计时还大于-1秒就继续调用
            if(respawnSecond[index-1] > -1 )
                // 这里做了一个递归函数（因为我发现官方的Task方法很奇怪，当使用循环时，会将时间和结果堆叠在一起并在一个方法结束后输出）
                // 每一秒调用一次计时方法
                Schedule::Task(1.0f,index,tip);
            else{
                // 倒计时归零，结束递归，转调用复活玩家的方法
                respawnPlayer(index);
            }
        }
    }
}

//复活玩家
void respawnPlayer(int index){
    //重置被复活玩家的复活时间值
    respawnSecond[index-1] = second;
    CTerrorPlayer@ pPlayer = ToTerrorPlayer( index );
    if ( pPlayer is null ) return;
    // 修改被复活玩家的游戏阵营
    pPlayer.ChangeTeam( TEAM_SURVIVOR );
    // 复活玩家
    pPlayer.Respawn();
    // 提示玩家复活
    Chat.CenterMessage(all, "["+pPlayer.GetPlayerName()+"]从石头里蹦出来了！(["+pPlayer.GetPlayerName()+"]has been resurrected)");
    // 输出测试信息
    Chat.PrintToConsole(all,"[Live]插件测试信息:"+pPlayer.GetPlayerName()+" 复活");
}


// 当幸存者玩家全部死亡
HookReturnCode OnNoSurvivorsRemaining( int iCandidate )
{
    // 匹配游戏模式，阻断默认的游戏结束事件（测试用）
	// If objective, then no game over
	// if ( iCandidate == GM_ESCAPE ) return HOOK_HANDLED;
    // if ( iCandidate == GM_FLATLINE ) return HOOK_HANDLED;
	// if ( iCandidate == GM_PANIC ) return HOOK_HANDLED;
	// if ( iCandidate == GM_EXTRACTION ) return HOOK_HANDLED;

    // 幸存者玩家全部死亡,中断所有复活方法（注释后游戏结束也不会停止复活，配合上方游戏结束事件使用，方便个人测试）
    gameover = true;
    // 输出测试信息
    Chat.PrintToConsole(all,"[Live]插件测试信息: 团灭失败");
    //重置复活计时数组，防止因游戏结束后部分玩家复活停止导致的数据变化
    respawnSecond = respawnSecondConst;
	return HOOK_CONTINUE;
}

// 当玩家断开连接后
HookReturnCode OnPlayerDisconnected(CTerrorPlayer@ pPlayer)
{
    if ( pPlayer is null ) 
        return HOOK_HANDLED;
    int index = pPlayer.entindex();
    // 将复活标识设为false,防止BUG
    canRespawn[index-1] = false;
    // 重置掉该玩家槽位的复活时间
    respawnSecond[index-1] = second;
    // 控制台输出测试信息
    //Chat.PrintToConsole(all,"[Live]插件测试信息:"+pPlayer.GetPlayerName()+" 退出游戏");
    // 清空槽位经验值
    exp[ pPlayer.entindex()-1 ] = 0;
    //Chat.PrintToChat(all,"当前玩家人数为:{gold}"+Utils.CollectPlayers().length());
	zombieConstant();
	return HOOK_CONTINUE;
}

// 实体掉落
HookReturnCode OnEntityDropped(CTerrorPlayer@ pPlayer, CBaseEntity@ pEntity)
{
    if(pEntity.ClassnameIs("item_ammo_*")){
        pEntity.SUB_Remove();
    }
    return HOOK_CONTINUE;
}

// 实体创建（删除金钱BUFF掉的钱）
HookReturnCode OnEntityCreation(const string &in strClassname, CBaseEntity@ pEntity)
{
    //Chat.PrintToChat(all,"实体创造："+strClassname);
    Log.PrintToServerConsole(LOGTYPE_INFO,"ent_create:"+strClassname);
    if( strClassname == "item_money" ){
        pEntity.SUB_Remove();
    }
	return HOOK_CONTINUE;
}

// 清除所有枪和子弹(除了任务道具和木板)
HookReturnCode OnRandomItemSpawn(const string &in strClassname, CBaseEntity@ pEntity)
{
    if( Utils.StrContains("weapon_",strClassname) && strClassname != "weapon_boltcutter" 
    &&strClassname != "weapon_extinguisher" && strClassname != "weapon_firstaid" && strClassname != "weapon_gasmask" 
    && strClassname != "weapon_glowstick" && strClassname != "weapon_grenade" && strClassname != "weapon_ied" 
    && strClassname != "weapon_inoculator" && strClassname != "weapon_itemcarry" && strClassname != "weapon_key" 
    && strClassname != "weapon_keycard" && strClassname != "weapon_nailgun" && strClassname != "weapon_torch" 
    && strClassname != "weapon_ied"){
        Log.PrintToServerConsole(LOGTYPE_INFO,"item_delete:"+strClassname);
        pEntity.SUB_Remove();
    }
    if( Utils.StrContains("item_ammo_",strClassname) && strClassname != "item_ammo_barricade" ){
        pEntity.SUB_Remove();
    }
    //Log.PrintToServerConsole(LOGTYPE_INFO,"item_create:"+strClassname);
	return HOOK_CONTINUE;
}

//-------------------------------------------------加僵尸-------------------------------------------------------
